package com.szr.leex.common.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;

public class SFTPUtil {
    /**
     * 调测日志记录器。
     */
    private static final Logger logger = LoggerFactory.getLogger(SFTPUtil.class);

    /**
     * Sftp客户端对象
     */
    private ChannelSftp sftp = null;

    /**
     * SFTP IP地址
     */
    private String ip;

    /**
     * SFTP 端口
     */
    private String port;

    /**
     * SFTP 用户名
     */
    private String userName;

    /**
     * SFTP 密码
     */
    private String password;

    /**
     * SFTP上传模式:BINARY 
     */
    // private static final int BINARY_FILE_TYPE = 2; 

    /**
     * 获取实例
     *
     * @return SFTPTool newinstance实例
     */
    public static SFTPUtil getNewInstance() {
        return new SFTPUtil();
    }

    /**
     * 初始化连接参数
     *
     * @param sftpIP       IP
     * @param sftpPort     端口
     * @param sftpUsername 用户名
     * @param sftpPassword 密码
     */
    public void init(String sftpIP, String sftpPort, String sftpUsername, String sftpPassword) {
        // 获取SFTP连接信息 
        this.ip = sftpIP;
        this.port = sftpPort;
        this.userName = sftpUsername;
        this.password = sftpPassword;
    }


    /**
     * 连接sftp服务器
     *
     * @param sftpip       ip地址
     * @param sftpport     端口
     * @param sftpusername 用户名
     * @param sftppassword 密码
     * @return channelSftp
     */
    public ChannelSftp connect(String sftpip, int sftpport, String sftpusername, String sftppassword) {
        sftp = new ChannelSftp();
        try {
            JSch jsch = new JSch();
            jsch.getSession(sftpusername, sftpip, sftpport);
            Session sshSession = jsch.getSession(sftpusername, sftpip, sftpport);
            logger.info("sftp session created");
            sshSession.setPassword(sftppassword);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            // 设置超时时间为 
            sshSession.setTimeout(300 * 1000);
            sshSession.connect();
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;
        } catch (JSchException e) {
            logger.error("JSchException : {}", e);
            throw new RuntimeException("JSchException:", e);
        }
        return sftp;
    }

    /**
     * 创建指定文件夹
     *
     * @param dirName dirName
     */
    public void mkDir(String dirName) {
        String[] dirs = dirName.split("/");
        try {
            String now = sftp.pwd();
            for (int i = 0; i < dirs.length; i++) {
                boolean dirExists = openDir(dirs[i]);
                if (!dirExists) {
                    sftp.mkdir(dirs[i]);
                    sftp.cd(dirs[i]);

                }

            }
            sftp.cd(now);
        } catch (SftpException e) {
            logger.error("mkDir Exception : " + e);
        }
    }

    /**
     * 打开指定目录
     *
     * @param directory directory
     * @return 是否打开目录
     */
    public boolean openDir(String directory) {
        try {
            sftp.cd(directory);
            return true;
        } catch (SftpException e) {
            logger.error("openDir Exception : " + e);
            return false;
        }
    }


    /**
     * 创建指定文件夹
     *
     * @param directory 路径+文件夹名
     * @return 成功与否
     */
    /*public boolean openAndMakeDir(String directory) {
        try {
            String now = sftp.pwd();
            if (now.equals(directory)) {
                return true;
            } else {
                try {
                    sftp.cd(directory);
                    return true;
                } catch (SftpException e) {
                    if (directory.startsWith(now)) {
                        directory = directory.replaceFirst(now, "");
                    }
                    String[] dirList = directory.split("/");
                    dirList = (String[]) ArrayUtils.removeElement(dirList, "");
                    for (String dir : dirList) {
                        try {
                            sftp.cd(dir);
                        } catch (SftpException e1) {
                            sftp.mkdir(dir);
                            sftp.cd(dir);
                        }
                    }
                    return true;
                }
            }
        } catch (SftpException e) {
            logger.error("openDir Exception : " + directory, e);
            return false;
        }
    }*/

    /**
     * 上传文件
     *
     * @param directory   上传的目录
     * @param file        要上传的文件 parentDir 上传目录的上级目录
     * @param ftpFileName 上传到ftp上的文件名称 如果问空，则使用file的name
     * @return 是否上传
     * @throws Exception
     */
    public boolean uploadFile(String directory, File file, String ftpFileName) throws Exception {
        boolean flag = false;
        FileInputStream in = null;

        if (null == ftpFileName) {
            ftpFileName = file.getName();
        }
        try {
            String now = sftp.pwd();
            sftp.cd(directory);
            in = new FileInputStream(file);
            sftp.put(in, ftpFileName);
            sftp.cd(now);
            if (file.exists()) {
                flag = true;
            } else {
                flag = false;
            }
        } catch (Exception e) {
            logger.error("uploadFile Exception : " + e);
            throw new Exception("上传文件到ftp失败，path：" + directory + ",fileName:" + ftpFileName);
        } finally {
            try {
                if (null != in) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        logger.error("IOException : " + e);
                    }
                }
            } catch (Exception e) {
                logger.error("Exception : " + e);
            }
        }
        return flag;
    }

    public boolean uploadFile(String directory, File file, String ftpFileName, String realName) throws Exception {
        boolean flag = false;
        FileInputStream in = null;

        if (null == ftpFileName) {
            ftpFileName = file.getName();
        }
        try {
            String now = sftp.pwd();
            sftp.cd(directory);
            in = new FileInputStream(file);
            sftp.put(in, ftpFileName);

            sftp.rename(ftpFileName, realName);

            sftp.cd(now);
            if (file.exists()) {
                flag = true;
            } else {
                flag = false;
            }
        } catch (Exception e) {
            logger.error("uploadFile Exception : " + e);
            throw new Exception("上传文件到ftp失败，path：" + directory + ",fileName:" + ftpFileName);
        } finally {
            try {
                if (null != in) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        logger.error("IOException : " + e);
                    }
                }
            } catch (Exception e) {
                logger.error("Exception : " + e);
            }
        }
        return flag;
    }

    /**
     * 下载文件.
     *
     * @param ftpDir        存放下载文件的SFTP路径
     * @param locDir        下载的文件 SFTP上的文件名称
     * @param ftpFileName   FTP上的文件名称
     * @param deleteFtpFile the delete ftp file
     * @return 本地文件对象
     * @throws Exception
     */
    public File download(String ftpDir, String locDir, String ftpFileName, boolean deleteFtpFile) {
        File file;
        FileOutputStream output = null;
        String locFileName = ftpFileName;
        String localPathAndFileName = new StringBuffer(formatPath(locDir))/*.append(File.separator) */
                .append(locFileName).toString();
        try {
            String now = sftp.pwd();
            sftp.cd(ftpDir);
            file = new File(localPathAndFileName);
            output = new FileOutputStream(file);
            sftp.get(ftpFileName, output);
            sftp.cd(now);
            if (deleteFtpFile) {
                sftp.rm(ftpFileName);
            }
        } catch (FileNotFoundException e){
            logger.error("下载sftp文件失败, FileNotFoundException:{}", locDir + locFileName);
            throw new RuntimeException("FileNotFoundException:", e);
        } catch (SftpException e) {
            logger.error("下载sftp文件失败:{}", ftpDir + ftpFileName);
            throw new RuntimeException("SftpException:", e);
        } finally {
            if (null != output) {
                try {
                    output.close();
                } catch (IOException e) {
                    logger.error("create localFile failed:" + e);
                }
            }
        }
        return file;
    }

    /**
     * Description:断开FTP连接 <br>
     *
     * @throws JSchException
     */
    public void disconnect() {
        if (null != sftp && sftp.isConnected()) {
            sftp.disconnect();

            try {
                if (null != sftp.getSession()) {
                    sftp.getSession().disconnect();
                }
            } catch (JSchException e) {
                logger.error("JSchException:{}", e);
            }
        }
    }

    /**
     * 删除文件
     *
     * @param directory  要删除文件所在目录
     * @param deleteFile 要删除的文件
     */
    public void delete(String directory, String deleteFile) {
        try {
            String now = sftp.pwd();
            sftp.cd(directory);
            sftp.rm(deleteFile);
            sftp.cd(now);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 列出目录下的文件
     *
     * @param directory 要列出的目录
     * @param regex     指定文件名的格式
     * @return 文件列表
     * @throws SftpException SftpException
     */
    @SuppressWarnings("unchecked")
    public List<String> listFiles(String directory, String regex)
            throws SftpException {
        List<String> ftpFileNameList = new ArrayList<String>();
        Vector<LsEntry> sftpFile = sftp.ls(directory);
        LsEntry isEntity = null;
        String fileName = null;
        Iterator<LsEntry> sftpFileNames = sftpFile.iterator();
        while (sftpFileNames.hasNext()) {
            isEntity = (LsEntry) sftpFileNames.next();
            fileName = isEntity.getFilename();

            if (regex == null || "".equals(regex)) {
                ftpFileNameList.add(fileName);
            } else {
                if (fileName.matches(regex)) {
                    ftpFileNameList.add(fileName);
                }
            }
        }

        return ftpFileNameList;
    }

    /**
     * 校验remotePath路径下的文件fileName是否存在
     */
    public boolean checkExist(String remotePath, String fileName){
        try {
            SftpATTRS attributes = sftp.lstat(remotePath + fileName);
            if (attributes != null){
                return true;
            }
        } catch (SftpException e) {
            logger.error("list sftp file error:" + remotePath + fileName, e);
        }
        return false;
    }

    public InputStream getInputStream(String remotePath, String fileName) throws SftpException {
        return sftp.get(formatPath(remotePath) + fileName);
    }

    public ChannelSftp getSftp() {
        return sftp;
    }

    public void setSftp(ChannelSftp sftp) {
        this.sftp = sftp;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    public static void main(String[] args) throws Exception {
        SFTPUtil tool = SFTPUtil.getNewInstance();
        ChannelSftp connect = tool.connect("10.10.43.9", 22, "djsftp", "dj@nybank1234");
        tool.uploadFile("/djxj/payment", new File("E:\\1.txt"), "2.txt");
        tool.disconnect();
//    	tool.download("/mysftp/contract", "E:\\", "Contract0400220161111.txt", false);
    }

    private String formatPath(String path) {
        if (null == path || "".equals(path)) {
            return "";
        }
        if (!path.endsWith("/")) {
            return path + "/";
        }
        return path;
    }
}
